home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 2002-05-17 | 34.7 KB | 1,198 lines
#!/usr/local/bin/perl use DBI; use CGI qw/:standard :escape :unescape/; # $external_prefix is the prefix to append to lockssl-on.gif and thankyou_url if necessary. # If you want to use "/files/lockssl-on.gif" and "/files/thankyou.html" then $external_prefix # must be set to '/files/' $external_prefix = ''; $email_alert = 'support@3d3.com'; # email in case of fatal error $back_url = 'http://www.3d3.com/enter.html?target=Products.html'; $mailusing = 'sendmail'; $mailprog = '/bin/sendmail'; $smtp_addr = '127.0.0.1'; $pgp_tmp = "/tmp/pgporder.$$"; $pgp_cmd = '/usr/local/bin/pgpe'; $pgp_opt = '-fa +batchmode +force +NoBatchInvalidKeys=0'; $database = 'regdb'; $user = 'x3d3'; $passwd = '4dcubed'; # valid referers @referers = ('.*regdb_order\.cgi'); # required fields @required = ("order_email", "order_pairs"); &parse_form(); &get_date(); &check_referer() or &show_errors('bad_referer'); (&check_required() or &show_errors('missing_fields', @ERROR)) if not @ERROR; &decode_order($FORM{'order_pairs'}); $is_upgrade = ($HEAD{'UPGRADECODE'} ? 1 : 0); $code = $HEAD{'SHOPORDER'}; (&validate_code() or &show_errors('Invalid code', @ERROR)) if not @ERROR; (&process_order() or &send_error_email()) if not @ERROR; if($FORM{'redirect_only'} ne "true") { &send_email(); &print_html(); } else { &redirect(); } sub process_order { my $done = 0; # connect to the database $dbh = DBI->connect("DBI:mysql:$database", $user, $passwd); if ($dbh) { # check if the code already exists if (&check_code($dbh, $HEAD{'EXISTINGCODE'})) { # It does not exist , or it is being replaced. Add it to the database. if (&insert_items($dbh)) { # At this point, we have successfully inserted the items. # Now we need to insert the customer data. if (&insert_customer($dbh)) { $done = 1; } } } $dbh->disconnect; } else { &show_errors('\$dbh->connect() Failed', ('Unable to connect to database', $dbh->errstr)); } return $done; } sub validate_code { my ($ok) = 0; # check code for length = 12, all numbers or du-nnn-n+ if ( (not ($code =~ /^[0-9]{12}?$/)) && (not ($code =~ /^[a-z]{2}?-[0-9]{3}?-[0-9]+?$/)) ) { push(@ERROR, "The code that came through with your order was corrupted"); } else { $ok = 1; } return $ok; } sub insert_items { my($dbh) = @_; my($ok) = 1; my ($customerName) = $dbh->quote($CUSTOMER{'NAME'}); my ($customerEmail) = $dbh->quote($CUSTOMER{'EMAIL'}); foreach $key (keys %ITEM) { # Here $key is the Item Number eg: "Pro4", or if an item is an upgrade, # it is something like "Lite3-Pro4" where "Lite3" is the original item, # and "Pro4" is the new item. my ($product, $version, $old_product, $old_version); my($item_upgrade) = 0; my(@item_numbers) = split(/-/, $key); if($#item_numbers == 1) { # It's an upgrade ($old_product) = ($item_numbers[0] =~ /^(\w+)[0-9]+$/); ($old_version) = ($item_numbers[0] =~ /^\w+([0-9]+)$/); ($product) = ($item_numbers[1] =~ /^(\w+)[0-9]+$/); ($version) = ($item_numbers[1] =~ /^\w+([0-9]+)$/); $item_upgrade = 1; } elsif($#item_numbers >= 0) { # It's a normal product ($product) = ($item_numbers[0] =~ /^(\w+)[0-9]+$/); ($version) = ($item_numbers[0] =~ /^\w+([0-9]+)$/); } else { # Something really weird happened... die("split failed on $key"); } my($strupgrade, $strextra); if($item_upgrade) { $strupgrade = $dbh->quote("$old_product $old_version to $product $version"); $strextra = $dbh->quote("Original Code was $HEAD{'UPGRADECODE'}"); } else { $strupgrade = "''"; $strextra = "''"; } my ($option); if($ITEM{$key}{'OPTION'}) { $option = $dbh->quote($ITEM{$key}{'OPTION'}); } else { $option = "''"; } # Here we have $FORM{'reseller_id'}, which is either the ResellerID from # the database (not Mid), or 'undefined'. # We may also have HEAD{'CLICKTHROUGH'}. # If $FORM{'reseller_id'} is valid, HEAD{'CLICKTHROUGH'} will be the # Mid of that reseller. We should not need to validate this. # If $FORM{'reseller_id'} is not valid, and HEAD{'CLICKTHROUGH'} exists, # it is an affiliate ID, and should be put in the Extra Info field. # The ResellerID for that product should be set to "Affiliate". # Really, we should be ignoring $FORM{'reseller_id'} and have a function # to determine the correct data to insert based on HEAD{'CLICKTHROUGH'} my($resellerId) = '0'; my($requestCust) = '0'; # Request customer details if we don't have their street. # We are checking street because we may already have their name and nothing # else. if(!$CUSTOMER{'STREET'} || $CUSTOMER{'STREET'} eq '') { $requestCust = '1'; } if ($FORM{'clickthrough'} eq '0101') { $resellerId = ($FORM{'reseller_id'} or 0); $strextra = $dbh->quote('fc101'); } elsif($FORM{'reseller_id'}) { if($FORM{'reseller_id'} ne 'undefined') { $resellerId = ($FORM{'reseller_id'} or 0); $requestCust = '1'; } } elsif ($FORM{'clickthrough'}) { $strextra = $dbh->quote('Affiliate'); my($sql) = qq[SELECT ResellerID from Reseller Where Mid = ].$dbh->quote($FORM{'clickthrough'}); my($sth) = $dbh->prepare($sql); if($sth) { if($sth->execute) { if($sth->rows != 0) { $hashref = $sth->fetchrow_hashref; $resellerId = $$hashref{'ResellerID'}; } } else { &show_errors('$sth->execute() Failed', ($sth->errstr, $sql)); $ok = 0; last; } } else { &show_errors('$dbh->prepare() Failed', ($dbh->errstr)); $ok = 0; last; } } my ($strdate) = "'$year-" . ($mon+1) . "-$mday $hour:$min:$sec'"; my ($sql) =<<"__EOSQL__"; INSERT INTO Reg (Code, ProductID, Version, ResellerID, Name, Email, Paid, Quantity, Options, Upgrade, ExtraInfo, Date, RequestCust) SELECT '$code', ProductID, $version, $resellerId, $customerName, $customerEmail, 0, $ITEM{$key}{'QUANTITY'}, $option, $strupgrade, $strextra, $strdate, $requestCust FROM Product WHERE Product.Name='$product' __EOSQL__ my($sth) = $dbh->prepare($sql); if($sth) { if(!$sth->execute) { &show_errors('$sth->execute() Failed', ($sth->errstr, $sql)); $ok = 0; last; } } else { &show_errors('$dbh->prepare() Failed', ($dbh->errstr)); $ok = 0; last; } if($item_upgrade) { # If it's an upgrade, we need to delete the existing record # We should also remove orphaned customer detail records if applicable. my($product_id) = get_product_id($dbh, $old_product); if($product_id > 0) { my($where) = 'Code=' . $dbh->quote($HEAD{'UPGRADECODE'}); $where .= ' AND ProductID=' . $dbh->quote($product_id); $where .= ' AND Version=' . $dbh->quote($old_version); &delete_records($dbh, 'Reg', $where); } } } return $ok; } sub insert_customer { my($dbh) = @_; # List of fields to insert: my($fields) =<<"__EOFIELDS__"; Code,CustomerName,CustomerCompany,CustomerStreet, CustomerCity,CustomerState,CustomerZip,CustomerCountry, CustomerPhone,CustomerFax,CustomerEmail,CustomerNotice __EOFIELDS__ # Values to insert: my($values) = "'$code',"; $values .= $dbh->quote($CUSTOMER{'NAME'}) . ','; $values .= $dbh->quote($CUSTOMER{'COMPANY'}) . ','; $values .= $dbh->quote($CUSTOMER{'STREET'}) . ','; $values .= $dbh->quote($CUSTOMER{'CITY'}) . ','; $values .= $dbh->quote($CUSTOMER{'STATE'}) . ','; $values .= $dbh->quote($CUSTOMER{'ZIP'}) . ','; $values .= $dbh->quote($CUSTOMER{'COUNTRY'}) . ','; $values .= $dbh->quote($CUSTOMER{'PHONE'}) . ','; $values .= $dbh->quote($CUSTOMER{'FAX'}) . ','; $values .= $dbh->quote($CUSTOMER{'EMAIL'}) . ','; $values .= $dbh->quote($CUSTOMER{'NOTICE'}); # Add delivery details if applicable: if( ($DELIVERY{'NAME'}) && ($DELIVERY{'NAME'} ne " ") ) { # add comma to end of $fields and to end of $values $fields .=<<"__EOFIELDS__"; ,DeliveryName,DeliveryCompany,DeliveryStreet,DeliveryCity, DeliveryState,DeliveryZip,DeliveryCountry,DeliveryPhone __EOFIELDS__ $values .= ','; $values .= $dbh->quote($DELIVERY{'NAME'}) . ','; $values .= $dbh->quote($DELIVERY{'COMPANY'}) . ','; $values .= $dbh->quote($DELIVERY{'STREET'}) . ','; $values .= $dbh->quote($DELIVERY{'CITY'}) . ','; $values .= $dbh->quote($DELIVERY{'STATE'}) . ','; $values .= $dbh->quote($DELIVERY{'ZIP'}) . ','; $values .= $dbh->quote($DELIVERY{'COUNTRY'}) . ','; $values .= $dbh->quote($DELIVERY{'PHONE'}) . ''; } my($sql) = "INSERT INTO Customer ($fields) VALUES ($values)"; my($ok) = 0; my($sth) = $dbh->prepare($sql); if($sth) { if($sth->execute) { $ok = 1; } else { &show_errors('$sth->execute() Failed', ($sth->errstr)); } } else { &show_errors('$dbh->prepare() Failed', ($dbh->errstr)); } return $ok; } sub get_product_id { my($dbh, $name) = @_; my($product_id) = 0; my($sql) = "SELECT ProductID FROM Product WHERE Name=" . $dbh->quote($name); my($sth) = $dbh->prepare($sql); if($sth) { if($sth->execute) { my($hashref); if($hashref = $sth->fetchrow_hashref) { $product_id = $$hashref{'ProductID'}; } $sth->finish; } } return($product_id); } sub check_code { my($dbh, $existingcode) = @_; my($newcode) = $code; my($rval) = 1; if($existingcode) { $rval = 0; # We have an existing code... replace it my($sql) = "SELECT * FROM Reg WHERE Code = '$existingcode'"; my($sth) = $dbh->prepare($sql); if($sth) { if($sth->execute) { if($sth->rows > 0) { # The code exists... my($hashref) = $sth->fetchrow_hashref; if($$hashref{'Paid'} == 0) { # Not paid for, we can replace it # Delete whatever is already there, from both the Reg # table and the Customer table if(&delete_records($dbh, 'Reg', "Code='$existingcode'")) { if(&delete_records($dbh, 'Customer', "Code='$existingcode'")) { # Everything's fine... $rval = 1; $newcode = $existingcode; } } } else { # Paid for, don't touch it. $rval = 1; } } else { # The existing code does not already exist... ignore it $rval = 1; } $sth->finish; } else { &show_errors('$sth->execute() Failed', ($sth->errstr)); } } else { &show_errors('$dbh->prepare() Failed', ($dbh->errstr)); } } if($rval) { $rval = 0; my($sql) = "SELECT * FROM Reg WHERE Code = '$newcode'"; my($sth) = $dbh->prepare($sql); if($sth) { if($sth->execute) { if($sth->rows == 0) { # ok, it's unique $rval = 1; } else { &show_errors('Non-unique Order ID', $newcode); } $sth->finish; } else { &show_errors('$sth->execute() Failed', ($sth->errstr)); } } else { &show_errors('$dbh->prepare() Failed', ($dbh->errstr)); } } $code = $newcode; return $rval; } sub delete_records { my($dbh, $table, $where) = @_; my($ok) = 0; if( (!$dbh) || (!$table) || (!$where) ) { return 0; } my($sql) = "DELETE FROM $table WHERE $where"; my($sth) = $dbh->prepare($sql); if($sth) { if($sth->execute) { $ok = 1; } else { &show_errors('$sth->execute() failed', ($sth->errstr)); } } else { &show_errors('$dbh->prepare() failed', ($dbh->errstr)); } return $ok; } sub get_date { my @days = ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); my @months = ('January','February','March','April','May','June','July','August','September','October','November','December'); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); if ($hour < 10) { $hour = "0$hour"; } if ($min < 10) { $min = "0$min"; } if ($sec < 10) { $sec = "0$sec"; } $year += 1900; if($FORM{'date_format'}) { $date = $FORM{'date_format'}; my($m_adj) = $mon + 1; if($m_adj < 10) { $m_adj = "0$m_adj"; } my($d_adj) = $mday; if($d_adj < 10) { $d_adj = "0$d_adj"; } $date =~ s/([yY]{4}?)/$year/eg; $date =~ s/([mM]{2}?)/$m_adj/eg; $date =~ s/([dD]{2}?)/$d_adj/eg; $date .= ", $hour\:$min\:$sec"; } else { $date = "$days[$wday], $months[$mon] $mday, $year, $hour\:$min\:$sec"; } } sub send_email { if($FORM{'recipient'} eq "") { print "Content-type: text/html\n\n"; print "<html"; if ($CONFIG{'html_lang'}) { print " lang=\"$CONFIG{'html_lang'}\""; } if ($CONFIG{'html_dir'}) { print " dir=\"$CONFIG{'html_dir'}\""; } print ">\n"; print "<head>\n"; if ($CONFIG{'http_charset'}) { print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$CONFIG{'http_charset'}\">\n"; } print "</head>\n"; print "<body"; &body_attributes; print ">\n"; print "<center><img src=\"" . $external_prefix . "lockssl-on.gif\"></center><br>\n"; print "<br><br><br><br><center>\n"; print "<font size=\"+2\">$FORM{'ln_email_required'}</font><br><br>\n"; print "</center>"; print "</body>\n</html>"; die; } $FORM{'order_email'} =~ s/\\n/\r\n/g; $FORM{'order_email'} =~ s/\QCode:\E\s+[0-9a-z\-]+/Code: $code/g; my ($body); if ($FORM{'clickthrough'}) { $body .= "Mid = " . $FORM{'clickthrough'} . " \n"; } if ($FORM{'keywords'}) { $body .= "Keyword = " . $FORM{'keywords'} . " \n"; } if ($FORM{'clickcost'}) { $body .= "Click-cost = " . $FORM{'clickcost'} . " \n"; } $to = "$FORM{'customer_email'}"; if($FORM{'email_from_field'} eq ("OFF")) { $from = "$FORM{'customer_email'}"; } else { $from = "$FORM{'recipient'}"; } $subject = "$FORM{'ln_orderfrom'} $FORM{'shopname'}"; $body .= "----------------------------------------\r\n"; $body .= "$FORM{'ln_orderfrom'} $FORM{'shopname'}\r\n"; $body .= "$FORM{'ln_submitted'}: $FORM{'customer_name'}\r\n"; $body .= "$FORM{'ln_email'}: $FORM{'customer_email'}\r\n"; $body .= "$FORM{'ln_date'}: $date\r\n"; $body .= "----------------------------------------\r\n\r\n"; $body .= "***** Payment for this order has not been approved\n"; $body .= "***** After approving payment, please go to\n"; $body .= "***** http://www.3d3.com/regdb/ to grant download\n"; $body .= "***** access to the customer.\n\n"; $body .= "$FORM{'order_email'}\r\n"; $body .= "\r\n----- $FORM{'ln_payment_method'} -----\r\n"; while (($key,$value) = each %FORM) { if ($key =~ "field_") { ($temp = $key) =~ s/field_//g; $body .= "$temp: $value\r\n"; } } $body .= "\r\n----- $FORM{'ln_total'} -----\r\n"; $body .= "$FORM{'ln_total_weight'}: $FORM{'total_weight'}\r\n"; $body .= "$FORM{'ln_purchase_price'}: $FORM{'currency_symbol'}$FORM{'total_ex_tax'}\r\n"; $body .= "$FORM{'ln_total_tax'}: $FORM{'currency_symbol'}$FORM{'tax_value'}\r\n"; $body .= "$FORM{'ln_total_shipping'}: $FORM{'currency_symbol'}$FORM{'shipping_value'}\r\n"; $body .= "$FORM{'ln_total_inc'}: $FORM{'currency_symbol'}$FORM{'total_inc_tax'}\r\n"; $body .= "\r\nBrowser: $ENV{'HTTP_USER_AGENT'}\r\n"; $body .= "Remote Host: $ENV{'REMOTE_HOST'}\r\n"; $body .= "Remote Address: $ENV{'REMOTE_ADDR'}\r\n"; $date =~ s/,/-/g; $FORM{account} =~ s/nigel's spuddly idea/$date/g; $FORM{account} =~ s/snippy and chad/$pay/g; if (!&sendmail($to, $from, $subject, $body, $FORM{account}, 1)) { # 1 = encrypt if PGP key supplied return; } # check for @ symbol before sending email if ($FORM{'dont_email_customer'} ne "true") { if ($FORM{'customer_email'} =~ "\@") { $to = "$FORM{'recipient'}"; $from = "$FORM{'customer_email'}"; $subject = "$FORM{'ln_confirm'} $FORM{'shopname'}"; $body = "----------------------------------------\r\n"; $body .= "$FORM{'ln_confirm'} $FORM{'shopname'}\r\n"; $body .= "$FORM{'ln_submitted'}: $FORM{'customer_name'}\r\n"; $body .= "$FORM{'ln_email'}: $FORM{'customer_email'}\r\n"; $body .= "$FORM{'ln_date'}: $date\r\n"; $body .= "----------------------------------------\r\n\r\n"; $body .= "$FORM{'order_email'}\r\n"; $body .= "\r\n----- $FORM{'ln_total'} -----\r\n"; $body .= "$FORM{'ln_total_weight'}: $FORM{'total_weight'}\r\n"; $body .= "$FORM{'ln_purchase_price'}: $FORM{'currency_symbol'}$FORM{'total_ex_tax'}\r\n"; $body .= "$FORM{'ln_total_tax'}: $FORM{'currency_symbol'}$FORM{'tax_value'}\r\n"; $body .= "$FORM{'ln_total_shipping'}: $FORM{'currency_symbol'}$FORM{'shipping_value'}\r\n"; $body .= "$FORM{'ln_total_inc'}: $FORM{'currency_symbol'}$FORM{'total_inc_tax'}\r\n"; $body .= "\r\nBrowser: $ENV{'HTTP_USER_AGENT'}\r\n"; $body .= "Remote Host: $ENV{'REMOTE_HOST'}\r\n"; $body .= "Remote Address: $ENV{'REMOTE_ADDR'}\r\n"; &sendmail($to, $from, $subject, $body); } } } sub send_error_email { my($body); $body = "$date\n"; $body .= "Error: $error\n"; foreach $field (@error_fields) { $body .= "$field \n"; } $body .="\n----- Data -----\n\n"; $body .= "%HEAD = {\n"; foreach $key (keys %HEAD) { $body .= " $key = $HEAD{$key}\n"; } $body .= "}\n"; $body .= "%ITEM = {\n"; foreach $key (keys %ITEM) { $body .= " $key = {\n"; foreach $ind (keys %{ $ITEM{$key} }) { $body .= " $ind = $ITEM{$key}{$ind}\n"; } $body .= " }\n"; } $body .= "}\n"; $body .= "%CUSTOMER = {\n"; foreach $key (keys %CUSTOMER) { $body .= " $key = $CUSTOMER{$key}\n"; } $body .= "}\n"; $body .= "%DELIVERY = {\n"; foreach $key (keys %DELIVERY) { $body .= " $key = $DELIVERY{$key}\n"; } $body .= "}\n"; $body .= "%SHPTAX = {\n"; foreach $key (keys %SHPTAX) { $body .= " $key = $SHPTAX{$key}\n"; } $body .= "}\n"; $body .= "%TTL = {\n"; foreach $key (keys %TTL) { $body .= " $key = $TTL{$key}\n"; } $body .= "}\n"; $body .= "\n----- Param Info -----\n\n"; # Send any specified Environment Variables to recipient. # map { $body .= "$_: $FORM{$_}\n" } sort(keys(%FORM)); $body .= "\n"; map { $body .= "$_: $CONFIG{$_}\n" } sort(keys(%CONFIG)); $body .= "\n"; map { $body .= "$_: $ENV{$_}\n" } sort(keys(%ENV)); $body .= "\n"; $body .= "\n----- UA Info -----\n\n"; $body .= "Browser: $ENV{'HTTP_USER_AGENT'}\n"; $body .= "Remote Host: $ENV{'REMOTE_HOST'}\n"; $body .= "Remote Address: $ENV{'REMOTE_ADDR'}\n"; &sendmail($email_alert, "\"regdb_email\" <$email_alert>", "regdb_email error!", $body); } sub print_html { print "Content-type: text/html\n\n"; print "<html"; if ($CONFIG{'html_lang'}) { print " lang=\"$CONFIG{'html_lang'}\""; } if ($CONFIG{'html_dir'}) { print " dir=\"$CONFIG{'html_dir'}\""; } print ">\n"; print "<head>\n"; if ($CONFIG{'http_charset'}) { print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$CONFIG{'http_charset'}\">\n"; } print "<meta http-equiv=\"refresh\" content=\"3;url=$FORM{'thankyou_url'}\">\n"; print "</head>\n"; print "<body"; &body_attributes; print ">\n"; print "<center><img src=\"" . $external_prefix . "lockssl-on.gif\"></center><br>\n"; print "<br><br><br><br><center>\n"; print "<font size=\"+2\">$FORM{'ln_secure_final'}.</font><br><br>\n"; print "<font size=\"-1\"><a href=\"$FORM{'thankyou_url'}\">$FORM{'ln_next'}</a></font>\n"; print "</center>"; print "</body>\n</html>"; } sub redirect { print "Location: $FORM{'thankyou_url'}\n\n"; } sub check_referer { my $referer_ok = 0; if ($ENV{'HTTP_REFERER'}) { foreach my $referer (@referers) { if ($ENV{'HTTP_REFERER'} =~ /$referer/i) { $referer_ok = 1; last; } } } else { $referer_ok = 1; } return $referer_ok; } sub check_required { while (@ERROR) { pop(@ERROR); } foreach $require (@required) { if ($require eq 'bgcolor' || $require eq 'background' || $require eq 'text_color' || $require eq 'link_color' || $require eq 'alink_color' || $require eq 'vlink_color') { if (!($CONFIG{$require}) || $CONFIG{$require} eq ' ') { push(@ERROR, $require); } } elsif (!($FORM{$require}) || $FORM{$require} eq ' ') { push(@ERROR, $require); } } return ($#ERROR+1 ? 0 : 1); } # # decode_order # # takes a name-value pair order email and turns it into some hashes: # $HEAD{} # $ITEM{} including $OPTIONS[]{} for each item # $CUSTOMER{} # $DELIVERY{} # $SHIPPINGTAX{} # $TOTAL{} # sub decode_order { my($order) = @_; my(@lines) = split(/[\r|\n]/, $order); my(@itemarr) = (); foreach $line (@lines) { chomp($line); if($line) { my($name, $value) = split(/=/, $line); $value =~ s/(\r|\n)*//g; $value = unescape($value); if($name) { my($hashname, $elemname) = ($name =~ /^([A-Z]+)[_]([\w]+)/); if($hashname ne "ITEM") { # not an item, just add it to the hash eval("\$$hashname\{'$elemname'\} = \$value;"); } else { # it is an item, get the number and the name my($itemnum, $itemname) = ($elemname =~ /^([0-9]+)[_]([\w]+)/); # fix $itemnum $itemnum--; if($itemname =~ "OPTION") { my($optionnum, $optionname) = ($itemname =~ /^[A-Z]+[_]([0-9]+)[_]([\w]+)/); # fix $optionnum; $optionnum--; $itemarr[$itemnum]{'OPTION'}[$optionnum]{$optionname} = $value; } else { $itemarr[$itemnum]{$itemname} = $value; } } } } } # at this point, we have an array of items, and need to consolidate them into a hash for $i (0 .. $#itemarr) { for $key ( keys %{ $itemarr[$i] } ) { if ($key =~ "OPTION") { for $j (0 .. $#{ $itemarr[$i]{'OPTION'} } ) { $ITEM{$itemarr[$i]{'ORDER_NUMBER'}}{$key} .= $itemarr[$i]{'OPTION'}[$j]{'NAME'}; $ITEM{$itemarr[$i]{'ORDER_NUMBER'}}{$key} .= '='; $ITEM{$itemarr[$i]{'ORDER_NUMBER'}}{$key} .= $itemarr[$i]{'OPTION'}[$j]{'VALUE'}; foreach $optkey (keys %{ $itemarr[$i]{'OPTION'}[$j] }) { if ( ($optkey ne 'NAME') && ($optkey ne 'VALUE') ) { $ITEM{$itemarr[$i]{'ORDER_NUMBER'}}{$key} .= ",$optkey="; $ITEM{$itemarr[$i]{'ORDER_NUMBER'}}{$key} .= $itemarr[$i]{'OPTION'}[$j]{$optkey}; } } $ITEM{$itemarr[$i]{'ORDER_NUMBER'}}{$key} .= ';'; } } elsif ($key eq "QUANTITY") { $ITEM{$itemarr[$i]{'ORDER_NUMBER'}}{$key} += $itemarr[$i]{$key}; } else { $ITEM{$itemarr[$i]{'ORDER_NUMBER'}}{$key} = $itemarr[$i]{$key}; } } } } sub parse_form { if ($ENV{'REQUEST_METHOD'} =~ 'GET') { @pairs = split(/&/, $ENV{'QUERY_STRING'}); # Split the name-value pairs } elsif ($ENV{'REQUEST_METHOD'} =~ 'POST') { read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); # Get the input @pairs = split(/&/, $buffer); # Split the name-value pairs } else { &show_errors('request_method'); } foreach $pair (@pairs) { ($name, $value) = split(/=/, $pair); # Split pair into name and value $name =~ tr/+/ /; # un-URL-encode the name $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $value =~ tr/+/ /; # un-URL-encode the value $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; $value =~ s/<!--(.|\n)*-->//g; # remove possible SSI directives from value if ($name eq 'mail_encoding' || $name eq 'http_charset' || $name eq 'mail_charset' || $name eq 'html_lang' || $name eq 'html_dir' || $name eq 'bgcolor' || $name eq 'background' || $name eq 'text_color' || $name eq 'link_color' || $name eq 'alink_color' || $name eq 'vlink_color' && ($value)) { $CONFIG{$name} = $value; } else { if ($FORM{$name} && ($value)) { $FORM{$name} = "$FORM{$name}, $value"; } elsif ($value) { $FORM{$name} = $value; } } } # defaults if(!$FORM{'ln_badreferer'}) { $FORM{'ln_badreferer'} = 'Bad Referrer - Access Denied'; } if(!$FORM{'ln_badreferer_desc'}) { $FORM{'ln_badreferer_desc'} = 'The URL of the form that is trying to use this CGI application is not in the list of valid referrers.'; } if(!$FORM{'ln_error_missing'}) { $FORM{'ln_error_missing'} = 'Missing Fields'; } if(!$FORM{'ln_error'}) { $FORM{'ln_error'} = 'Error'; } if(!$FORM{'ln_orderfrom'}) { $FORM{'ln_orderfrom'} = 'Order from'; } if(!$FORM{'ln_submitted'}) { $FORM{'ln_submitted'} = 'Submitted by'; } if(!$FORM{'ln_email'}) { $FORM{'ln_email'} = 'email'; } if(!$FORM{'ln_date'}) { $FORM{'ln_date'} = 'date'; } if(!$FORM{'ln_confirm'}) { $FORM{'ln_confirm'} = 'Order confirmation from'; } if(!$FORM{'ln_pgp_failed'}) { $FORM{'ln_pgp_failed'} = 'PGP Encryption Failed. Check your User ID.'; } if(!$FORM{'ln_userid_sub'}) { $FORM{'ln_userid_sub'} = 'The User ID submitted was:'; } # fix thankyou_url if necessary if($FORM{'thankyou_url'} eq 'thankyou.html') { $FORM{'thankyou_url'} = $external_prefix . 'thankyou.html'; } # set default mail charset if(!$CONFIG{'mail_charset'}) { $CONFIG{'mail_charset'} = $CONFIG{'http_charset'}; } } sub show_errors { ($error, @error_fields) = @_; print "Content-type: text/html\n\n"; print "<html"; if ($CONFIG{'html_lang'}) { print " lang=\"$CONFIG{'html_lang'}\""; } if ($CONFIG{'html_dir'}) { print " dir=\"$CONFIG{'html_dir'}\""; } print ">\n"; print "<head>\n"; if ($CONFIG{'http_charset'}) { print "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$CONFIG{'http_charset'}\">\n"; } print "</head>\n"; print "<body"; &body_attributes; print ">\n"; if ($error eq 'bad_referer') { print "<center>\n<h1>$FORM{'ln_badreferer'}</h1>\n</center>\n"; print "$FORM{'ln_badreferer_desc'}\n"; } elsif ($error eq 'request_method') { print "<center>\n<h1>Invalid Request Method</h1>\n</center>\n"; print "The Request Method of the submitted form did not match\n"; print "either GET or POST.<p>\n"; } elsif ($error eq 'missing_fields') { print "<center>\n<h1>$FORM{'ln_error_missing'}</h1>\n</center>\n"; print "$FORM{'ln_error_fields'}:<p>\n"; print "<ul>\n"; foreach $missing_field (@error_fields) { print "<li>$missing_field\n"; } print "</ul>\n"; } else { print "<center>\n<h1>$FORM{'ln_error'}: $error</h1>\n</center>\n"; foreach $field (@error_fields) { print "$field<br>"; } } print "</body>\n</html>\n"; exit; } sub body_attributes { if ($CONFIG{'bgcolor'}) { print " bgcolor=\"$CONFIG{'bgcolor'}\""; } if ($CONFIG{'background'} =~ /http\:\/\/.*\..*/) { print " background=\"$CONFIG{'background'}\""; } if ($CONFIG{'link_color'}) { print " link=\"$CONFIG{'link_color'}\""; } if ($CONFIG{'vlink_color'}) { print " vlink=\"$CONFIG{'vlink_color'}\""; } if ($CONFIG{'alink_color'}) { print " alink=\"$CONFIG{'alink_color'}\""; } if ($CONFIG{'text_color'}) { print " text=\"$CONFIG{'text_color'}\""; } } sub sendmail { my($to, $from, $subject, $body, $attach, $encrypt) = @_; my($encodedbody, $encodedsubject); # Here we PGP encrypt the body if applicable if($encrypt && $FORM{'pgp_user'}) { my($pgp_user) = $FORM{'pgp_user'}; chomp($pgp_user); $body = &pgp_encrypt($body, $pgp_user); $attach = &pgp_encrypt($attach, $pgp_user) if defined $attach; } if($CONFIG{'mail_charset'} && $CONFIG{'mail_encoding'}) { if($encrypt && $FORM{'pgp_user'}) { if(defined $attach) { $encodedbody = "Mime-Version: 1.0\r\n" . "Content-Type: multipart/mixed;\r\n" . qq' boundary="endofmail"\r\n\r\n' . "This is a multi-part message in MIME format.\r\n" . "--endofmail\r\n" . "Content-Type: application/pgp\r\n" . "Content-Disposition: \r\n$body\r\n\r\n" . "--endofmail\r\n" . "Content-Type: application/pgp\r\n" . "Content-Disposition: attachment\r\n\r\n$attach\r\n\r\n" . "--endofmail--\r\n"; } else { $encodedbody = "Mime-Version: 1.0\r\n\r\n$body"; } } else { $encodedbody = &encode($body, $CONFIG{'mail_charset'}, $CONFIG{'mail_encoding'}); } $encodedsubject = &encode_header($subject, $CONFIG{'mail_charset'}, $CONFIG{'mail_encoding'}, 40); } else { if(defined $attach) { $encodedbody = "Mime-Version: 1.0\r\n" . "Content-Type: multipart/mixed;\r\n" . qq' boundary="endofmail"\r\n\r\n' . "This is a multi-part message in MIME format.\r\n" . "--endofmail\r\n" . "Content-Type: text/plain\r\n" . "Content-Disposition: \r\n$body\r\n\r\n" . "--endofmail\r\n" . "Content-Type: text/plain\r\n" . "Content-Disposition: attachment\r\n\r\n$attach\r\n\r\n" . "--endofmail--\r\n"; } else { $encodedbody = "\r\n" . $body; $encodedsubject = $subject; } $encodedsubject = $subject; } if (lc $mailusing eq 'sendmail') { open (MAIL, "|$mailprog -t") || &show_errors("Can't open $mailprog!"); print MAIL "To: $to\r\n"; print MAIL "From: $from\r\n"; print MAIL "Subject: $encodedsubject\r\n"; print MAIL "$encodedbody\r\n"; close MAIL; } else { $err = &sockets_mail($to, $from, $encodedsubject, $encodedbody); if ($err < 1) { &show_errors("SMTP error # $err"); return 0; } } return 1; } sub pgp_encrypt { my($in_text, $pgp_user) = @_; my($out_text) = ''; # # We are piping the output of pgp to null. stderr ends up in the web server's error log. # We should capture both of these, and display them to the user, if applicable # if( open(PGP, "|$pgp_cmd -r \"${pgp_user}\" $pgp_opt -o $pgp_tmp > /dev/null") ) { print PGP $in_text; close(PGP); if( open(CRYPTTMP, "<${pgp_tmp}") ) { while(<CRYPTTMP>) { $out_text .= $_; } close(CRYPTTMP); `rm -f ${pgp_tmp}`; } else { # # If we get to here, it means $pgp_tmp could not be opened for reading. # This will usually be because pgp did not create an output file, which # is probably because pgp was given a non-existent user id. # # We send the email anyway, with a warning at the top. # $out_text = "$FORM{'ln_pgp_failed'}\r\n"; $out_text .= "$FORM{'ln_userid_sub'}\r\n"; $out_text .= "$pgp_user\r\n\r\n"; $out_text .= $in_text } } else { # # If we get to here, it means we couldn't fork $pgp_cmd. Check the path to # pgp defined at the top of this file. Also check the web server error log. &show_errors("Can't run PGP"); } return($out_text); } sub sockets_mail { my ($to, $from, $subject, $message) = @_; my ($replyaddr) = $from; if (!$to) { return -8; } my ($proto, $port, $smptaddr); my ($AF_INET) = 2; my ($SOCK_STREAM) = 1; $proto = (getprotobyname('tcp'))[2]; $port = 25; $smtpaddr = ($smtp_addr =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/) ? pack('C4',$1,$2,$3,$4) : (gethostbyname($smtp_addr))[4]; if (!defined($smtpaddr)) { return -1; } if (!socket(S, $AF_INET, $SOCK_STREAM, $proto)) { return -2; } if (!connect(S, pack('Sna4x8', $AF_INET, $port, $smtpaddr))) { return -3; } select(S); $| = 1; select(STDOUT); $_ = <S>; if (/^[45]/) { close S; return -4; } print S "helo localhost\r\n"; $_ = <S>; if (/^[45]/) { close S; return -5; } print S "mail from: $from\r\n"; $_ = <S>; if (/^[45]/) { close S; return -5; } print S "rcpt to: $to\r\n"; $_ = <S>; if (/^[45]/) { close S; return -6; } print S "data\r\n"; $_ = <S>; if (/^[45]/) { close S; return -5; } print S "Content-Type: text/plain; charset=us-ascii\r\n"; print S "To: $to\r\n"; print S "From: $from\r\n"; print S "Reply-to: $replyaddr\r\n" if $replyaddr; print S "Subject: $subject\r\n"; print S "$message"; print S "\r\n.\r\n"; $_ = <S>; if (/^[45]/) { close S; return -7; } print S "quit\r\n"; $_ = <S>; close S; return 1; } sub encode { my($body, $charset, $encoding) = @_; my($r); if( ($encoding =~ 'Quoted-Printable') || ($encoding =~ 'Base64') ) { $r = "MIME-Version: 1.0\r\n"; $r .= "Content-Type: text/plain; charset=$charset\r\n"; $r .= "Content-transfer-encoding: $encoding\r\n\r\n"; if($encoding =~ 'Quoted-Printable') { $r .= &encode_qp($body); } else { $r .= &encode_base64($body,"\n",76); } } else { $r = "\r\n$body"; } return($r); } # Encodes a header line as either Base64 or modified Quoted-Prinable # as per RFC 2047. $maxlen is the maximum length of the encoded part # of the string. If the encoded string exceeds this length, the # remainder will be appended after CRLF SPACE sub encode_header { my($text, $charset, $encoding, $maxlen) = @_; my($r) = ""; my($e, $t); if($encoding =~ 'Quoted-Printable') { $e = encode_head_qp($text, $maxlen); $t = 'Q'; } elsif ($encoding =~ 'Base64') { $e = encode_base64($text, "\n", $maxlen); $t = 'B'; } if($e) { my(@el) = split(/\n/, $e); for $i (0 .. $#el) { $r .= "=?$charset?$t?$el[$i]?="; if($i != $#el) { $r .= "\r\n "; } } } else { $r = $text; } return($r); } # stolen from MIME::Base64.pm and modified to include max length sub encode_base64 ($;$;$) { my $res = ""; my $eol = $_[1]; $eol = "\n" unless defined $eol; my $maxlen = $_[2]; $maxlen = 76 unless defined $maxlen; pos($_[0]) = 0; # ensure start at the beginning while ($_[0] =~ /(.{1,45})/gs) { $res .= substr(pack('u', $1), 1); chop($res); } $res =~ tr|` -_|AA-Za-z0-9+/|; # `# help emacs # fix padding at the end my $padding = (3 - length($_[0]) % 3) % 3; $res =~ s/.{$padding}$/'=' x $padding/e if $padding; # break encoded string into lines of no more than 76 characters each if (length $eol) { $res =~ s/(.{1,$maxlen})/$1$eol/g; } $res; } # stolen from MIME::QuotedPrint.pm sub encode_qp ($) { my $res = shift; $res =~ s/([^ \t\n!-<>-~])/sprintf("=%02X", ord($1))/eg; # rule #2,#3 $res =~ s/([ \t]+)$/ join('', map { sprintf("=%02X", ord($_)) } split('', $1) )/egm; # rule #3 (encode whitespace at eol) # rule #5 (lines must be shorter than 76 chars, but we are not allowed # to break =XX escapes. This makes things complicated :-( ) my $brokenlines = ""; $brokenlines .= "$1=\n" while $res =~ s/(.*?^[^\n]{73} (?: [^=\n]{2} (?! [^=\n]{0,1} $) # 75 not followed by .?\n |[^=\n] (?! [^=\n]{0,2} $) # 74 not followed by .?.?\n | (?! [^=\n]{0,3} $) # 73 not followed by .?.?.?\n ))//xsm; "$brokenlines$res"; } # modified encode_qp for doing headers. Includes max length sub encode_head_qp ($;$) { my $res = $_[0]; my $maxlen = $_[1]; $res =~ s/([^A-Za-z0-9!*+\-\/=_])/sprintf("=%02X", ord($1))/eg; $res =~ s/([ \t]+)$/ join('', map { sprintf("=%02X", ord($_)) } split('', $1) )/egm; my $brokenlines = ""; $maxlen -= 3; $brokenlines .= "$1\n" while $res =~ s/(.*?^[^\n]{$maxlen} (?: [^=\n]{2} (?! [^=\n]{0,1} $) |[^=\n] (?! [^=\n]{0,2} $) | (?! [^=\n]{0,3} $) ))//xsm; "$brokenlines$res"; }